export interface FetchQueueOption {
  /** 最大执行数量 */
  maxNum?: number;
  /** 队列执行完后回调，全局监听 */
  callback?: QueueCallback;
}

type QueueFn = () => Promise<any>;

type QueueCallback = () => any;

export interface QueuesData extends FetchQueueOption {
  /** 队列函数 */
  queueFn: QueueFn;
  resolve: (value?: any) => void;
  reject: (value?: any) => void;
}

/**
 * 队列类
 ```js
const queueDemo = new FetchQueue({
  // 指定上限，超过会进入队列机制
  maxNum: 2,
  // 全局监听成功回调
  callback: () => {
    const newData = Object.fromEntries(cacheSelectOptions.entries())
    setAllFieldOptions(newData)
    setLoading(false)
  }
}) 
 
// 添加一条队列，并且会自动执行
queueDemo.addQueue(() => {
  setTimeout(() => {
    console.log(`结果${i}`)
  }, 1000)
})

// 批量添加队列
queueDemo.addQueues([
  () => {
    // 接口请求1
  },
  () => {
    // 接口请求2
  },
])

// 局部监听成功后
queueDemo.on('complete', ()=>{
  console.log('成功回调');
})
 ```
 */
export class FetchQueue {
  private queue: QueuesData[] = [];

  private currentNumber = 0;

  private maxNum = 6;

  private queueStatus: 'stop' | 'start' = 'stop';

  private callback?: QueueCallback;

  private events: Map<string, QueueCallback[]> = new Map();

  constructor(data: FetchQueueOption) {
    const { maxNum, callback } = data || {};
    if (maxNum) this.maxNum = maxNum;
    if (callback) this.callback = callback;
  }

  /** 监听事件回调 */
  on = (eventName: 'complete', callback: QueueCallback) => {
    if (!this.events.has(eventName)) {
      this.events.set(eventName, []);
    }
    const datas = this.events.get(eventName) || [];
    datas?.push(callback);
    this.events.set(eventName, datas);
  };

  private omit = (eventName: 'complete') => {
    if (this.events.has(eventName)) {
      const datas = this.events.get(eventName);
      datas?.forEach((itemCb) => {
        itemCb?.();
      });
    }
  };

  /**
   * 批量添加队列
   */
  addQueues = (allQueue: QueueFn[]) => {
    for (let i = 0; i < allQueue.length; i++) {
      const itemQueue = allQueue[i];
      // eslint-disable-next-line no-new
      new Promise((resolve, reject) => {
        this.queue.push({
          resolve,
          reject,
          queueFn: itemQueue,
        });
      });
    }
    this.getOneQueue();
    // if (this.queueStatus === 'stop') this.startQueue()
  };

  /** 增加一个队列 */
  addQueue = (queueFn: QueueFn) => {
    return new Promise((resolve, reject) => {
      this.queue.push({
        resolve,
        reject,
        queueFn,
      });
      this.getOneQueue();
      // if (this.queueStatus === 'stop') this.startQueue()
    });
  };

  /**
   * 开始执行队列，默认addQueue添加队列时就会执行
   */
  startQueue = async () => {
    if (this.queueStatus === 'start') return;
    this.queueStatus = 'start';
    const { maxNum } = this;
    const startNum = this.queue.length > maxNum ? maxNum : this.queue.length;
    for (let i = 0; i < startNum; i++) {
      if (this.currentNumber <= maxNum) {
        this.getOneQueue();
      }
    }
  };

  private getOneQueue = () => {
    if (this.queue.length === 0 || this.currentNumber >= this.maxNum) {
      return;
    }
    const currentQueue = this.queue.shift();
    const { queueFn, resolve, reject } = currentQueue || {};
    ++this.currentNumber;
    queueFn?.()
      .then((res) => {
        --this.currentNumber;
        resolve?.(res);
      })
      .catch((err) => {
        --this.currentNumber;
        reject?.(err);
      })
      .finally(() => {
        if (this.queue.length === 0 && this.currentNumber === 0) {
          this.queueStatus = 'stop';
          this.callback?.();
          this.omit('complete');
          return;
        }
        this.getOneQueue();
      });
  };
}
